////////////////////////////////////////////////////////////////////////////////
//
//  FLYING KIWI BV
//  Copyright 2010 Flying Kiwi BV
//  All Rights Reserved.
//
//  NOTICE: Flying Kiwi permits you to use, modify, and distribute this file
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package plantool.core {
	import flash.desktop.NativeApplication;
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.geom.Point;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLStream;
	import flash.utils.ByteArray;
	
	import kiwi.components.Button;
	
	import plantool.data.DatabaseManager;
	import plantool.data.DatabaseTypes;
	import plantool.data.IDatabaseController;
	import plantool.data.sqlite.SQLiteController;
	import plantool.display.skins.DefaultButtonSkin;
	import plantool.display.splash.SplashScreen;
	import plantool.modules.calendar.Calendar;
	import plantool.modules.menu.Menu;
	import plantool.modules.users.Users;
	import plantool.modules.workplaces.Workplaces;

	//--------------------------------------------------------------------------
	//  Imports
	//--------------------------------------------------------------------------
	//--------------------------------------------------------------------------
	//  [Metadata (Events, Style, Effects etc)]
	//--------------------------------------------------------------------------
	[Event(name="complete", type="flash.events.Event")]
	
	//--------------------------------------------------------------------------
	//  Class declaration
	//--------------------------------------------------------------------------
	public class AirLauncher extends CoreModule {
		//--------------------------------------------------------------------------
		//Class constants
		//--------------------------------------------------------------------------
		private const NUM_APIS:uint			= 4;
		
		//--------------------------------------------------------------------------
		//Class variables
		//--------------------------------------------------------------------------
		private var _apiInitCount:uint		= 0;
		private var _moduleInitCount:uint	= 0;
		private var _splash:SplashScreen	= null;
		
		private var _updateFile:File		= null;
		private var _fileStream:FileStream	= null;
		private var _urlStream:URLStream	= null;
		
		//--------------------------------------------------------------------------
		//Class properties
		//--------------------------------------------------------------------------
		
		//--------------------------------------------------------------------------
		//Constructor and Destructor
		//--------------------------------------------------------------------------
		public function AirLauncher() {
			super();
		}
		
		//--------------------------------------------------------------------------
		//Class methods
		//--------------------------------------------------------------------------
		
		/*
		UPDATE FUNCTIONS
		*/
		private function checkForUpdate():void {
			var updateDescLoader:URLLoader = new URLLoader;
			updateDescLoader.addEventListener(Event.COMPLETE, updateDescLoader_completeHandler);
			updateDescLoader.addEventListener(IOErrorEvent.IO_ERROR, updateDescLoader_ioErrorHandler);
			updateDescLoader.load(new URLRequest("http://www.vdkrieken.nl/plantool_updates/update.xml"));
		}
		
		private function updateDescLoader_completeHandler(event:Event):void {
			var loader:URLLoader = URLLoader(event.currentTarget);
			
			// Closing update descriptor loader
			closeUpdateDescLoader(loader);
			
			// Getting update descriptor XML from loaded data
			var updateDescriptor:XML = XML(loader.data);
			// Getting default namespace of update descriptor
			var udns:Namespace = updateDescriptor.namespace();
			
			// Getting application descriptor XML
			var applicationDescriptor:XML = NativeApplication.nativeApplication.applicationDescriptor;
			// Getting default namespace of application descriptor
			var adns:Namespace = applicationDescriptor.namespace();
			
			// Getting versionNumber from update descriptor
			var updateVersion:String = updateDescriptor.udns::versionNumber.toString();
			// Getting versionNumber from application descriptor
			var currentVersion:String = applicationDescriptor.adns::versionNumber.toString();
			
			// Comparing current version with update version
			if (currentVersion != updateVersion) {
				// Getting update url
				var updateUrl:String = updateDescriptor.udns::url.toString();
				// Downloading update file
				downloadUpdate(updateUrl);
			} else {
				openDatabaseConnection();
			}
		}
		
		private function updateDescLoader_ioErrorHandler(event:IOErrorEvent):void {
			closeUpdateDescLoader(URLLoader(event.currentTarget));
		}
		
		private function closeUpdateDescLoader(loader:URLLoader):void {
			loader.removeEventListener(Event.COMPLETE			, updateDescLoader_completeHandler);
			loader.removeEventListener(IOErrorEvent.IO_ERROR	, updateDescLoader_ioErrorHandler);
			loader.close();
		}
		
		private function downloadUpdate(updateUrl:String):void {
			// Parsing file name out of the download url
			var fileName:String = updateUrl.substr(updateUrl.lastIndexOf("/") + 1);
			
			// Creating new file ref in temp directory
			_updateFile = File.createTempDirectory().resolvePath(fileName);
			
			// Using URLStream to download update file
			_urlStream = new URLStream;
			_urlStream.addEventListener(Event.OPEN				, urlStream_openHandler);
			_urlStream.addEventListener(ProgressEvent.PROGRESS	, urlStream_progressHandler);
			_urlStream.addEventListener(Event.COMPLETE			, urlStream_completeHandler);
			_urlStream.addEventListener(IOErrorEvent.IO_ERROR	, urlStream_ioErrorHandler);
			_urlStream.load(new URLRequest(updateUrl));
		}
		
		protected function urlStream_openHandler(event:Event):void {
			// Creating new FileStream to write downloaded bytes into
			_fileStream = new FileStream;
			_fileStream.open(_updateFile, FileMode.WRITE);
		}
		
		protected function urlStream_progressHandler(event:ProgressEvent):void {
			// ByteArray with loaded bytes
			var loadedBytes:ByteArray = new ByteArray;
			// Reading loaded bytes
			_urlStream.readBytes(loadedBytes);
			// Writing loaded bytes into the FileStream
			_fileStream.writeBytes(loadedBytes);
		}
		
		protected function urlStream_completeHandler(event:Event):void {
			// Closing URLStream and FileStream
			closeStreams();
			
			// Installing update
			installUpdate();
		}
		
		protected function installUpdate():void {
			// Running the installer using NativeProcess API
			var info:NativeProcessStartupInfo = new NativeProcessStartupInfo;
			info.executable = _updateFile;
			
			var process:NativeProcess = new NativeProcess;
			process.start(info);
			
			// Exit application for the installer to be able to proceed
			NativeApplication.nativeApplication.exit();
		}
		
		protected function urlStream_ioErrorHandler(event:IOErrorEvent):void {
			closeStreams();
			trace('URLSTREAM IOERROR');
		}
		
		protected function closeStreams():void {
			_urlStream.removeEventListener(Event.OPEN				, urlStream_openHandler);
			_urlStream.removeEventListener(ProgressEvent.PROGRESS	, urlStream_progressHandler);
			_urlStream.removeEventListener(Event.COMPLETE			, urlStream_completeHandler);
			_urlStream.removeEventListener(IOErrorEvent.IO_ERROR	, urlStream_ioErrorHandler);
			_urlStream.close();
			
			// Checking if FileStream was instantiated
			if (_fileStream)
				_fileStream.close();
		}
		
		/*
		END UPDATE FUNCTIONS
		*/
		
		private function initApis():void {
			//set status
			statusManager.status = "Initializing api's...";
			
			//init all api's
			userApi.addEventListener(Event.COMPLETE			, onComplete_api);
			userApi.install();
			dateApi.addEventListener(Event.COMPLETE			, onComplete_api);
			dateApi.install();
			workplaceApi.addEventListener(Event.COMPLETE	, onComplete_api);
			workplaceApi.install();
			orderApi.addEventListener(Event.COMPLETE		, onComplete_api);
			orderApi.install();
		}
		
		private function initCoreModules():void {
			//create the default modules
			base.stage.addChild(Calendar.getInstance());
			base.stage.addChild(Users.getInstance());
			base.stage.addChild(Workplaces.getInstance());
			base.stage.addChild(Menu.getInstance());
		}
		
		private function onComplete_api(e:Event):void {
			//remove eventlistener from api
			(e.currentTarget as CoreApi).removeEventListener(Event.COMPLETE		, onComplete_api);
			
			//increate api init count
			_apiInitCount++;
			
			//check if all core api's are loaded
			if (_apiInitCount == NUM_APIS) {
				onApis_initialized();
			}
		}
		
		private function onComplete_settings(e:Event):void {
			//remove complete event from settings
			settings.removeEventListener(Event.COMPLETE		, onComplete_settings);
			
			//init all api's
			initApis();
		}
		
		private function onConnection_ready(e:Event):void {
			//remove connection-ready event
			databaseManager.removeEventListener(DatabaseManager.CONNECTION_READY		, onConnection_ready);
			
			//load settings
			settings.addEventListener(Event.COMPLETE		, onComplete_settings);
		}
		
		private function onApis_initialized():void {
			//init core modules
			initCoreModules();
			
			//set status
			statusManager.status = "Modules initialized...";
			
			//start main application
//			base.stage.nativeWindow.width	= 1024;
//			base.stage.nativeWindow.height	= 768;
			base.stage.nativeWindow.minSize = new Point(1024, 768);
			
			//close the splash-screen
			_splash.close();
			_splash = null;
			
			//dispatch complete event
			dispatchEvent(new Event(Event.COMPLETE));
		}
		
		private function openDatabaseConnection():void {
			//create a databasecontroller based on the database type
			var controller:IDatabaseController		= null;
			switch (base.config.DATABASETYPE) {
				//create the SQLite Controller
				default:
				case DatabaseTypes.DATABASETYPE_SQLITE:
					controller = new SQLiteController();
					break;
			}
			
			//startup the database connection
			databaseManager.addEventListener(DatabaseManager.CONNECTION_READY		, onConnection_ready);
			databaseManager.setController(controller);
		}
		
		private function onSplash_activated(e:Event):void {
			//remove activate event
			_splash.removeEventListener(Event.ACTIVATE		, onSplash_activated);
			
			//set default button skin
			Button.defaultSkinClass = DefaultButtonSkin;
			
			//start updated
			checkForUpdate();
			
			//open the database connection
			//openDatabaseConnection();
		}
		
		protected override function init():void {
			//launch the splash screen
			_splash		= new SplashScreen();
			_splash.addEventListener(Event.ACTIVATE		, onSplash_activated);
			_splash.activate();
		}
	}
}